package com.enzoism.springboot.dive.service;

import com.alibaba.fastjson.JSON;
import com.enzoism.springboot.dive.model.SportModel;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.ScoreSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SportESService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;
    @Value("${elasticsearch.configs.sport.indexName}")
    private String indexName;

    /**
     * 新建索引
     */
    public void createIndex() {
        try {
            boolean exists = restHighLevelClient.indices().exists(new GetIndexRequest(indexName), RequestOptions.DEFAULT);
            if (!exists) {
                CreateIndexRequest qyf = new CreateIndexRequest(indexName);
                restHighLevelClient.indices().create(qyf, RequestOptions.DEFAULT);
            }
        } catch (Exception e) {
            log.error("ES操作失败", e);
        }
    }

    /**
     * 保存文档
     */
    public void saveDocument(SportModel sportModel) {
        IndexRequest request = new IndexRequest(indexName);

        request.source(JSON.toJSONString(sportModel), XContentType.JSON);
        request.id(sportModel.getTitle());
        request.timeout(TimeValue.timeValueSeconds(3000));
        try {
            IndexResponse index = restHighLevelClient.index(request, RequestOptions.DEFAULT);
            System.out.println(index);
        } catch (IOException e) {
            log.error("ES操作失败", e);
        }
    }

    /**
     * 根据ID获取文档
     */
    public String getDocument(SportModel sportModel) {
        GetRequest getRequest = new GetRequest(indexName, sportModel.getId());
        GetResponse getResponse1 = null;
        try {
            getResponse1 = restHighLevelClient.get(getRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("ES操作失败", e);
        }
        return Objects.requireNonNull(getResponse1).toString();
    }

    /**
     * 文档搜索
     */
    public List<Map<String, Object>> searchIndex(String index, int from, int size, Map<String, Object> where, Map<String, Boolean> sortFieldsToAsc, String[] includeFields, String[] excludeFields, int timeOut) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
        try {
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            //条件
            if (where != null && !where.isEmpty()) {
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                where.forEach((k, v) -> {
                    if (v instanceof Map) {
                        //范围选择map  暂定时间
                        Map<String, Date> mapV = (Map<String, Date>) v;
                        boolQueryBuilder.must(QueryBuilders.rangeQuery(k).gte(format.format(mapV.get("start"))).lt(format.format(mapV.get("end"))));
                    } else {
                        //普通模糊匹配
                        boolQueryBuilder.must(QueryBuilders.wildcardQuery(k, v.toString()));
                    }
                });
                sourceBuilder.query(boolQueryBuilder);
            }

            //分页
            from = from <= -1 ? 0 : from;
            size = Math.min(size, 1000);
            size = size <= 0 ? 15 : size;
            sourceBuilder.from(from);
            sourceBuilder.size(size);

            //超时
            sourceBuilder.timeout(new TimeValue(timeOut, TimeUnit.SECONDS));

            //排序
            if (sortFieldsToAsc != null && !sortFieldsToAsc.isEmpty()) {
                sortFieldsToAsc.forEach((k, v) -> {
                    sourceBuilder.sort(new FieldSortBuilder(k).order(v ? SortOrder.ASC : SortOrder.DESC));
                });
            } else {
                sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));
            }

            //返回和排除列
            if ((includeFields != null && includeFields.length != 0) || (excludeFields != null && excludeFields.length != 0)) {
                sourceBuilder.fetchSource(includeFields, excludeFields);
            }

            SearchRequest rq = new SearchRequest();
            //索引
            rq.indices(index);
            //各种组合条件
            rq.source(sourceBuilder);

            //请求
            System.out.println(rq.source().toString());
            SearchResponse rp = restHighLevelClient.search(rq, null);

            //解析返回
            if (rp.status() != RestStatus.OK || Objects.requireNonNull(rp.getHits().getTotalHits()).value <= 0) {
                return Collections.emptyList();
            }

            //获取source
            return Arrays.stream(rp.getHits().getHits()).map(SearchHit::getSourceAsMap).collect(Collectors.toList());

        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return Collections.emptyList();
    }

    /**
     * 分页搜索
     */
    public List<Map<String, Object>> searchPage(String keyword, int pageNo, int pageSize) throws IOException {

        SearchRequest searchRequest = new SearchRequest(indexName);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        pageNo = pageNo * pageSize;
        pageSize = pageSize == 0 ? 10 : pageSize;
        searchSourceBuilder.from(pageNo);
        searchSourceBuilder.size(pageSize);

        //输入的关键字匹配的字段
        QueryBuilder termQueryBuilder = QueryBuilders.matchQuery("content", keyword);

        searchSourceBuilder.query(termQueryBuilder);
        searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));

        //执行
        searchRequest.source(searchSourceBuilder);
        SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        ArrayList<Map<String, Object>> list = new ArrayList<>();

        if (search.getHits().getHits().length != 0) {
            for (SearchHit documentFields : search.getHits().getHits()) {
                list.add(documentFields.getSourceAsMap());
            }
            return list;
        } else {
            HashMap<String, Object> map = new HashMap<>();
            map.put("code", 404);
            map.put("msg", "没有相关数据");
            list.add(map);
            return list;
        }
    }
}